using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace EuropeEngulfed.NET
{
    //TODO Improve supply selection dialog
    //- Proper labels for remaining sea supply capacity
    //- combo boxes inside the list items
    partial class SupplySelectionDialog : Form
    {
        private const int BLOCK_ITEM_GAP = 15;

        private bool finalSupplySelection;
        private GameController europeEngulfedGame;
        private Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSea;
        private Dictionary<MapInfo.RegionID, int> seaSupplyPoints;
        private Dictionary<MapInfo.RegionID, int> seaSupplyRemaining;
        private Dictionary<MapInfo.CountryID, int> specialActions;
        private Dictionary<MapInfo.CountryID, int> specialActionsRemaining;
        private List<SupplySelectionMove> listOfSelections;

        public enum supplySelectionItemState 
        {
            unsupplied,
            suppliedBySea,
            suppliedBySpecialAction,
        }

        public class supplySelectionItem
        {
            public MapInfo.RegionID regionID;
            public PlayingPiece playingPiece;
            public supplySelectionItemState state;
            public List<GameController.SeaSupplySolution> seaRegionPaths;
            public int selectedSeaPathIndex;
            public bool inFriendlyControlledRegion;
            public supplySelectionItem(MapInfo.RegionID regionID, PlayingPiece playingPiece, supplySelectionItemState state, List<GameController.SeaSupplySolution> seaRegionPaths, bool inFriendlyControlledRegion)
            {
                int indexOfAroundTheCapeMedToRemove = 0;
                bool vanillaCapeFound = false;
                bool MedCapeFound = false;
                this.regionID = regionID;
                this.playingPiece = playingPiece;
                this.state = state;
                selectedSeaPathIndex = 0;
                this.seaRegionPaths = new List<GameController.SeaSupplySolution>(seaRegionPaths);
                foreach (GameController.SeaSupplySolution seaSupplySolution in this.seaRegionPaths)
                {
                    bool foundMed = false;
                    bool foundRedSea = false;
                    foreach(SeaRegion seaRegion in seaSupplySolution.seaRegionPath)
                    {
                        if (seaRegion.RegionID == MapInfo.RegionID.RedSea)
                            foundRedSea = true;
                        else if(seaRegion.RegionID == MapInfo.RegionID.MediteraneanSea)
                            foundMed = true;
                    }

                    if (foundMed && foundRedSea)
                    {
                        indexOfAroundTheCapeMedToRemove = this.seaRegionPaths.IndexOf(seaSupplySolution);
                        MedCapeFound = true;
                    }
                    else if (foundRedSea)
                        vanillaCapeFound = true;
                }

                if (vanillaCapeFound && MedCapeFound)
                    this.seaRegionPaths.RemoveAt(indexOfAroundTheCapeMedToRemove);
                this.inFriendlyControlledRegion = inFriendlyControlledRegion;
            }
        };

        public SupplySelectionDialog(List<SupplySelectionMove> listOfSelections,GameController europeEngulfedGame, bool finalSupplySelection, Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSea, Dictionary<MapInfo.RegionID, int> seaSupplyPoints, Dictionary<MapInfo.CountryID, int> specialActions)
        {
            this.finalSupplySelection = finalSupplySelection;
            this.regionsCountryOOSorUSingSea = regionsCountryOOSorUSingSea;
            InitializeComponent();
            this.SupplySelectionList.ItemHeight = PlayingPieceGraphics.GetBlockSize().Height + (BLOCK_ITEM_GAP * 2);
            this.SupplySelectionList.Font = new Font(FontFamily.GenericSerif, 25);
            if (!finalSupplySelection)
                this.specialActionGroup.Visible = false;

            this.europeEngulfedGame = europeEngulfedGame;
            this.SupplySelectionList.DrawItem += new DrawItemEventHandler(SupplySelectionList_DrawItem);
            this.seaSupplyRemaining = new Dictionary<MapInfo.RegionID, int>(seaSupplyPoints);
            this.seaSupplyPoints = new Dictionary<MapInfo.RegionID, int>(seaSupplyPoints);
            this.specialActions = new Dictionary<MapInfo.CountryID, int>(specialActions);
            this.specialActionsRemaining = new Dictionary<MapInfo.CountryID, int>(specialActions);
            this.listOfSelections = listOfSelections;
            foreach(MapInfo.RegionID regionID in regionsCountryOOSorUSingSea.Keys)
            {
                foreach(MapInfo.CountryID countryID in regionsCountryOOSorUSingSea[regionID].Keys)
                {
                    if(this.europeEngulfedGame.IsAxisCountry(countryID))
                    {
                        List<Block> blockList = this.europeEngulfedGame.GetRegionsAxisBlockList(regionID);
                        foreach(Block block in blockList)
                        {
                            if(block.CountryOwner == countryID)
                                this.SupplySelectionList.Items.Add(new supplySelectionItem(regionID,(PlayingPiece)(block.Copy()), supplySelectionItemState.unsupplied, regionsCountryOOSorUSingSea[regionID][countryID], europeEngulfedGame.IsAxisCountry(europeEngulfedGame.GetRegionControl(regionID))));
                        }

                        List<GroundSupportUnit> GSUList = this.europeEngulfedGame.GetRegionsAxisGSUList(regionID);
                        foreach(GroundSupportUnit GSU in GSUList)
                        {
                            if (GSU.CountryOwner == countryID)
                                this.SupplySelectionList.Items.Add(new supplySelectionItem(regionID, (PlayingPiece)(new GroundSupportUnit(GSU)), supplySelectionItemState.unsupplied, regionsCountryOOSorUSingSea[regionID][countryID], europeEngulfedGame.IsAxisCountry(europeEngulfedGame.GetRegionControl(regionID))));
                        }
                    }
                    else if(this.europeEngulfedGame.IsAlliedCountry(countryID))
                    {
                        List<Block> blockList = this.europeEngulfedGame.GetRegionsAlliedBlockList(regionID);
                        foreach (Block block in blockList)
                        {
                            if (block.CountryOwner == countryID)
                                this.SupplySelectionList.Items.Add(new supplySelectionItem(regionID, (PlayingPiece)block, supplySelectionItemState.unsupplied, regionsCountryOOSorUSingSea[regionID][countryID], europeEngulfedGame.IsAlliedCountry(europeEngulfedGame.GetRegionControl(regionID))));
                        }

                        List<GroundSupportUnit> GSUList = this.europeEngulfedGame.GetRegionsAlliedGSUList(regionID);
                        foreach (GroundSupportUnit GSU in GSUList)
                        {
                            if (GSU.CountryOwner == countryID)
                                this.SupplySelectionList.Items.Add(new supplySelectionItem(regionID, (PlayingPiece)GSU, supplySelectionItemState.unsupplied, regionsCountryOOSorUSingSea[regionID][countryID], europeEngulfedGame.IsAlliedCountry(europeEngulfedGame.GetRegionControl(regionID))));
                        }
                    }
                }
            }

            foreach(supplySelectionItem item in SupplySelectionList.Items)
            {
                if(item.seaRegionPaths.Count > 0)
                {
                    item.selectedSeaPathIndex = 0;
                    item.state = supplySelectionItemState.suppliedBySea;
                    item.playingPiece.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
                    RecalculateSeaSupply();
                    foreach (MapInfo.RegionID seaRegionID in seaSupplyPoints.Keys)
                    {
                        if(seaSupplyRemaining[seaRegionID] < 0)
                        {
                            item.state = supplySelectionItemState.unsupplied;
                            item.playingPiece.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                            break;
                        }
                    }
                }
            }

            RecalculateSeaSupply();
            this.seaSupplyTextBox.Text = GetSeaSupplyDisplayString();
            this.specialActionsRemainingTextBox.Text = GetSpecialActionsRemainingDisplayString();
        }

        public static bool IsAroundTheCapeSeaPath(List<SeaRegion> seaRegionPath)
        {
            foreach(SeaRegion seaRegion in seaRegionPath)
            {
                if (seaRegion.RegionID == MapInfo.RegionID.RedSea)
                    return true;
            }

            return false;
        }

        void SupplySelectionList_DrawItem(object sender, DrawItemEventArgs e)
        {
            supplySelectionItem item = (supplySelectionItem)this.SupplySelectionList.Items[e.Index];
            e.DrawBackground();
            if(item.playingPiece is Block)
            {
                PlayingPieceGraphics.PaintBlock(e.Graphics, (Block)item.playingPiece, new Point(e.Bounds.Location.X + BLOCK_ITEM_GAP + PlayingPieceGraphics.GetBlockSize().Width / 2, e.Bounds.Location.Y + BLOCK_ITEM_GAP + PlayingPieceGraphics.GetBlockSize().Height / 2), 1, false);
            }
            else if(item.playingPiece is GroundSupportUnit)
            {
                PlayingPieceGraphics.PaintGSU(e.Graphics, (GroundSupportUnit)item.playingPiece, new Point(e.Bounds.Location.X + BLOCK_ITEM_GAP + PlayingPieceGraphics.GetBlockSize().Width / 2, e.Bounds.Location.Y + BLOCK_ITEM_GAP + PlayingPieceGraphics.GetBlockSize().Height / 2));
            }

            e.Graphics.DrawString(MapInfo.GetRegionName(item.regionID), e.Font, new SolidBrush(Color.Black), new Point(e.Bounds.Location.X + (BLOCK_ITEM_GAP * 2) + PlayingPieceGraphics.GetBlockSize().Width, e.Bounds.Location.Y + PlayingPieceGraphics.GetBlockSize().Height / 2));
            switch(item.state)
            {
                case supplySelectionItemState.unsupplied:
                    e.Graphics.DrawString("Unsupplied", new Font("Century Gothic", 10), new SolidBrush(Color.Black), new RectangleF(e.Bounds.X + 300, e.Bounds.Y, this.SupplySelectionList.Width - 300, e.Bounds.Height - BLOCK_ITEM_GAP));
                    break;
                case supplySelectionItemState.suppliedBySea:
                    string seaSupply = "Supplied by sea through";
                    if(IsAroundTheCapeSeaPath(item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath))
                    {
                        if (item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath.Count > 2)
                            seaSupply = "Med->Around the Cape";
                        else
                            seaSupply = "Around the Cape";
                    }
                    else
                    {
                        for (int i = item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath.Count - 1; i >= 0; i--)
                        {
                            seaSupply += "->";
                            seaSupply += MapInfo.GetRegionName(item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath[i].RegionID);
                        }
                    }
                    if (item.seaRegionPaths[item.selectedSeaPathIndex].fromBeachHead)
                        seaSupply += "Beachhead";
                    e.Graphics.DrawString(seaSupply, new Font("Century Gothic", 10), new SolidBrush(Color.Black), new RectangleF(e.Bounds.X + 300, e.Bounds.Y, this.SupplySelectionList.Width - 300, e.Bounds.Height - BLOCK_ITEM_GAP));
                    break;
                case supplySelectionItemState.suppliedBySpecialAction:
                    e.Graphics.DrawString("Supplied by Special Action", new Font("Century Gothic", 10), new SolidBrush(Color.Black), new RectangleF(e.Bounds.X + 300, e.Bounds.Y, this.SupplySelectionList.Width - 300, e.Bounds.Height - BLOCK_ITEM_GAP));
                    break;
            }
        }

        private string GetSeaSupplyDisplayString()
        {
            string displayString = "";
            foreach (MapInfo.RegionID regionID in seaSupplyRemaining.Keys)
            {
                displayString += MapInfo.GetRegionName(regionID);
                displayString += " ";
                displayString += seaSupplyRemaining[regionID].ToString();
                displayString += "\r\n";
            }

            return displayString;
        }

        private string GetSpecialActionsRemainingDisplayString()
        {
            string displayString = "";
            foreach (MapInfo.CountryID countryID in this.specialActionsRemaining.Keys)
            {
                displayString += Enum.GetName(countryID.GetType(),countryID);
                displayString += " ";
                displayString += specialActionsRemaining[countryID].ToString();
                displayString += "\r\n";
            }

            return displayString;
        }

        private void SupplySelectionList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            supplySelectionItemState previousState = ((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).state;
            UnitSupplySelectionDialog dialog = new UnitSupplySelectionDialog((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex],seaSupplyRemaining, this.finalSupplySelection, this.specialActionsRemaining);
            dialog.ShowDialog();
            //If a supply by special action is changed we need to remove the same from all other blocks of the same country in the same region
            if (previousState == supplySelectionItemState.suppliedBySpecialAction && ((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).state != supplySelectionItemState.suppliedBySpecialAction)
            {
                foreach (supplySelectionItem item in SupplySelectionList.Items)
                {
                    if (item.state == supplySelectionItemState.suppliedBySpecialAction)
                    {
                        if (this.GetSpecialActionPayingCountry(item.playingPiece.CountryOwner) == this.GetSpecialActionPayingCountry(((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).playingPiece.CountryOwner))
                            if (item.regionID == ((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).regionID)
                            {
                                item.state = supplySelectionItemState.unsupplied;
                                item.playingPiece.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                            }
                    }
                }

                this.Invalidate();
            }
            else if (previousState != supplySelectionItemState.suppliedBySpecialAction && ((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).state == supplySelectionItemState.suppliedBySpecialAction)
            {
                foreach (supplySelectionItem item in SupplySelectionList.Items)
                {
                    if (item.state != supplySelectionItemState.suppliedBySpecialAction)
                    {
                        if (this.GetSpecialActionPayingCountry(item.playingPiece.CountryOwner) == this.GetSpecialActionPayingCountry(((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).playingPiece.CountryOwner))
                            if (item.regionID == ((supplySelectionItem)this.SupplySelectionList.Items[this.SupplySelectionList.SelectedIndex]).regionID)
                            {
                                item.state = supplySelectionItemState.suppliedBySpecialAction;
                                item.playingPiece.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
                            }
                    }
                }
                this.Invalidate();
            }
            RecalculateSeaSupply();
            RecalculateSpecialActions();
        }

        private void RecalculateSeaSupply()
        {
            foreach (MapInfo.RegionID seaRegionID in seaSupplyPoints.Keys)
            {
                seaSupplyRemaining[seaRegionID] = seaSupplyPoints[seaRegionID];
            }

            foreach(supplySelectionItem item in SupplySelectionList.Items)
            {
                if(item.state == supplySelectionItemState.suppliedBySea)
                {
                    if (IsAroundTheCapeSeaPath(item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath))
                    {
                        if(item.seaRegionPaths[item.selectedSeaPathIndex].fromBeachHead)
                        {
                            if (item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath.Count > 2)
                                seaSupplyRemaining[MapInfo.RegionID.MediteraneanSea] -= 2;
                            seaSupplyRemaining[MapInfo.RegionID.AtlanticOcean] -= 8;
                        }
                        else
                        {
                            if(item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath.Count > 2)
                                seaSupplyRemaining[MapInfo.RegionID.MediteraneanSea]--;
                            seaSupplyRemaining[MapInfo.RegionID.AtlanticOcean] -= 4;
                        }
                    }
                    else
                    {
                        foreach (SeaRegion seaRegion in item.seaRegionPaths[item.selectedSeaPathIndex].seaRegionPath)
                        {
                            if (item.seaRegionPaths[item.selectedSeaPathIndex].fromBeachHead)
                                seaSupplyRemaining[seaRegion.RegionID] -= 2;
                            else
                                seaSupplyRemaining[seaRegion.RegionID]--;
                        }
                    }
                }
            }

            this.seaSupplyTextBox.Text = GetSeaSupplyDisplayString();
        }

        private MapInfo.CountryID GetSpecialActionPayingCountry(MapInfo.CountryID country)
        {
            switch(country)
            {
                case MapInfo.CountryID.Rumania:
                case MapInfo.CountryID.Hungary:
                case MapInfo.CountryID.Finland:
                case MapInfo.CountryID.Bulgaria:
                    return MapInfo.CountryID.Germany;
                case MapInfo.CountryID.FreeFrance:
                    return MapInfo.CountryID.USA;
            }

            return country;
        }

        private void RecalculateSpecialActions()
        {
            Dictionary<MapInfo.CountryID, List<MapInfo.RegionID>> specialActionsSpent = new Dictionary<MapInfo.CountryID, List<MapInfo.RegionID>>();

            foreach (supplySelectionItem item in SupplySelectionList.Items)
            {
                if (item.state == supplySelectionItemState.suppliedBySpecialAction)
                {
                    if (!specialActionsSpent.ContainsKey(GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)))
                    {
                        specialActionsSpent.Add(GetSpecialActionPayingCountry(item.playingPiece.CountryOwner), new List<MapInfo.RegionID>());
                    }

                    if (!specialActionsSpent[GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)].Contains(item.regionID))
                        specialActionsSpent[GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)].Add(item.regionID);
                }
            }

            foreach (MapInfo.CountryID countryID in this.specialActions.Keys)
            {
                this.specialActionsRemaining[countryID] = this.specialActions[countryID];
            }

            foreach(MapInfo.CountryID country in specialActionsSpent.Keys)
            {
                this.specialActionsRemaining[country] -= specialActionsSpent[country].Count;
            }

            this.specialActionsRemainingTextBox.Text = GetSpecialActionsRemainingDisplayString();
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            foreach (supplySelectionItem item in SupplySelectionList.Items)
            {
                if(item.state == supplySelectionItemState.suppliedBySea)
                {
                    this.listOfSelections.Add(new SupplySelectionMove(this.europeEngulfedGame.GetCurrentGameDate(),this.europeEngulfedGame.GetCurrentGamePhase(),this.europeEngulfedGame.GetCurrentGameSubPhase(),item.regionID,item.playingPiece, item.seaRegionPaths[item.selectedSeaPathIndex]));
                }
            }

            if(this.finalSupplySelection)
            {
                Dictionary<MapInfo.CountryID, List<MapInfo.RegionID>> specialActionsSpent = new Dictionary<MapInfo.CountryID, List<MapInfo.RegionID>>();
                foreach (supplySelectionItem item in SupplySelectionList.Items)
                {
                    if (item.state == supplySelectionItemState.suppliedBySpecialAction)
                    {
                        if (!specialActionsSpent.ContainsKey(GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)))
                        {
                            specialActionsSpent.Add(GetSpecialActionPayingCountry(item.playingPiece.CountryOwner), new List<MapInfo.RegionID>());
                        }

                        if (!specialActionsSpent[GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)].Contains(item.regionID))
                            specialActionsSpent[GetSpecialActionPayingCountry(item.playingPiece.CountryOwner)].Add(item.regionID);
                    }
                }

                foreach(MapInfo.CountryID countryID in specialActionsSpent.Keys)
                {
                    foreach(MapInfo.RegionID regionID in specialActionsSpent[countryID])
                    {
                        this.listOfSelections.Add(new SupplySelectionMove(this.europeEngulfedGame.GetCurrentGameDate(), this.europeEngulfedGame.GetCurrentGamePhase(), this.europeEngulfedGame.GetCurrentGameSubPhase(), regionID, countryID));
                    }
                }
            }
            this.DialogResult = DialogResult.OK;
            this.Close();
        }

        private void eyeButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
    }
}